@import '../theming/theming';
@import '../theming/check-duplicate-styles';
@import '../style/layout-common';

/// Mixin that turns on strong focus indicators.
///
/// @example
///   .my-app {
///     @include mat-strong-focus-indicators($config);
///   }
@mixin mat-strong-focus-indicators($config: ()) {
  // Default focus indicator config.
  $default-config: (
    border-style: solid,
    border-width: 3px,
    border-radius: 4px,
  );

  // Merge default config with user config.
  $config: map-merge($default-config, $config);
  $border-style: map-get($config, border-style);
  $border-width: map-get($config, border-width);
  $border-radius: map-get($config, border-radius);

  // Base styles for focus indicators.
  .mat-focus-indicator::before {
    @include mat-fill();
    box-sizing: border-box;
    pointer-events: none;
    border: $border-width $border-style transparent;
    border-radius: $border-radius;
  }

  // By default, all focus indicators are flush with the bounding box of their
  // host element. For particular elements (listed below), default inset/offset
  // values are necessary to ensure that the focus indicator is sufficiently
  // contrastive and renders appropriately.

  .mat-focus-indicator.mat-flat-button::before,
  .mat-focus-indicator.mat-raised-button::before,
  .mat-focus-indicator.mat-fab::before,
  .mat-focus-indicator.mat-mini-fab::before,
  .mat-focus-indicator.mat-chip::before,
  .mat-focus-indicator.mat-sort-header-container::before {
    margin: -($border-width + 2px);
  }

  .mat-focus-indicator.mat-stroked-button::before,
  .mat-focus-indicator.mat-calendar-body-cell-content::before {
    margin: -($border-width + 3px);
  }

  .mat-focus-indicator.mat-tab-link::before,
  .mat-focus-indicator.mat-tab-label::before {
    margin: 5px;
  }

  // Render the focus indicator on focus. Defining a pseudo element's
  // content will cause it to render.

  // Checkboxes, radios, and slide toggles render focus indicators when the
  // associated visually-hidden input is focused.
  .mat-checkbox-input:focus ~ .mat-focus-indicator::before,
  .mat-radio-input:focus ~ .mat-focus-indicator::before,
  .mat-slide-toggle-input:focus ~ .mat-slide-toggle-thumb-container .mat-focus-indicator::before,

  // For options, render the focus indicator when the class .mat-active
  // is present.
  .mat-focus-indicator.mat-option.mat-active::before,

  // For calendar cells, render the focus indicator when the parent cell is
  // focused.
  .mat-calendar-body-cell:focus .mat-focus-indicator::before,

  // For all other components, render the focus indicator on focus.
  .mat-focus-indicator:focus::before {
    content: '';
  }
}

// Mixin that applies the border color for the focus indicators.
@mixin _mat-strong-focus-indicators-border-color($color) {
  .mat-focus-indicator::before {
    border-color: $color;
  }
}

@mixin mat-strong-focus-indicators-color($config-or-theme) {
  $config: mat-get-color-config($config-or-theme);
  @include _mat-strong-focus-indicators-border-color(mat-color(map_get($config, primary)));
}

/// Mixin that sets the color of the focus indicators.
///
/// @param {color|map} $theme-or-color
///   If theme, focus indicators are set to the primary color of the theme. If
///   color, focus indicators are set to that color.
///
/// @example
///   .demo-dark-theme {
///     @include mat-strong-focus-indicators-theme($dark-theme-map);
///   }
///
/// @example
///   .demo-red-theme {
///     @include mat-strong-focus-indicators-theme(#f00);
///   }
/* stylelint-disable-next-line material/theme-mixin-api */
@mixin mat-strong-focus-indicators-theme($theme-or-color) {
  @if type-of($theme-or-color) != 'map' {
    @include _mat-strong-focus-indicators-border-color($theme-or-color);
  }
  @else {
    $theme: _mat-legacy-get-theme($theme-or-color);
    @include _mat-check-duplicate-theme-styles($theme, 'mat-strong-focus-indicators') {
      $color: mat-get-color-config($theme);
      @if $color != null {
        @include mat-strong-focus-indicators-color($color);
      }
    }
  }
}

// Mixin that ensures focus indicator host elements are positioned so that the focus indicator
// pseudo element within is positioned relative to the host. Private mixin included within
// `mat-core`.
@mixin _mat-strong-focus-indicators-positioning() {
  .mat-focus-indicator {
    position: relative;
  }
}
